package com.sinai.mshab.client.util;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;

import com.google.gwt.user.client.rpc.IsSerializable;

/**
 * <code>AnswerCollection</code> maintains a collection of {@link Answer}
 * objects and acts similar to an {@link ArrayList}.
 * 
 * @see ArrayList
 * @author Arthur Kalmenson
 */
public class AnswerCollection implements IsSerializable {

	/**
	 * The list of <code>Answer</code>s. <b>Note:</b> This
	 * <code>ArrayList</code> can only contain <code>Answer</code> objects.
	 * 
	 * @gwt.typeArgs <com.sinai.mshab.client.util.Answer>
	 */
	private ArrayList answers;

	/**
	 * Creates a new empty <code>AnswerCollection</code>.
	 */
	public AnswerCollection() {
		answers = new ArrayList();
	}

	/**
	 * Creates a new <code>AnswerCollection</code> and adds
	 * <code>first_answer</code>.
	 * 
	 * @param first_answer
	 *            the initial <code>Answer</code> to add to the new
	 *            <code>AnswerCollection</code>.
	 */
	public AnswerCollection(Answer first_answer) {
		answers = new ArrayList();
		answers.add(first_answer);
	}

	/**
	 * Adds <code>answer</code> to the current <code>AnswerCollection</code>.
	 * 
	 * @param answer
	 *            the <code>Answer</code> to add.
	 */
	public void add(Answer answer) {
		answers.add(answer);
	}

	/**
	 * Returns the <code>Answer</code> object at index <code>index</code>.
	 * 
	 * @param index
	 *            the index of the requested <code>Answer</code> object.
	 * @return the <code>Answer</code> object at index <code>index</code>.
	 */
	public Answer get(int index) {
		if (index < answers.size()) {
			return (Answer) answers.get(index);
		}
		
		return null;
	}

	/**
	 * Returns the size of the current <code>AnswerCollection </code>.
	 * 
	 * @return the size of the current <code>AnswerCollection </code>.
	 */
	public int size() {
		return answers.size();
	}

	/**
	 * Returns whether this <code>AnswerCollection</code> is empty or not. It
	 * is considered empty if all of it's containing {@link Answer}s are empty.
	 * 
	 * @return whether this <code>AnswerCollection</code> is empty or not.
	 */
	public boolean isEmpty() {

		for (int i = 0; i < answers.size(); i++) {
			Answer answer = (Answer) answers.get(i);
			HashMap the_answer = answer.getHashMap();
			Iterator keys = the_answer.keySet().iterator();

			while (keys.hasNext()) {
				String key = (String) keys.next();
				if (((String) the_answer.get(key)).length() > 0) {
					return false;
				}
			}
		}
		return true;
	}

	/**
	 * Condesnses all answer objects into fewer answer objects by merging
	 * mergable answers of the same table name into 1 answer.
	 */
	public void pack() {
		HashMap table_to_answer = new HashMap();

		// going through all of our answers and grouping them based on table
		// name
		for (int i = 0; i < answers.size(); i++) {
			Answer current_answer = (Answer) answers.get(i);
			String table_name = current_answer.getTableName();

			// if the key already exists
			if (table_to_answer.containsKey(table_name)) {

				// if this answer is not mergable, simply append it to the list
				if (!current_answer.isMergeable()) {
					ArrayList widgets = (ArrayList) table_to_answer
							.get(table_name);
					widgets.add(current_answer);
				}
				// if this IS mergable, find the first mergable answer object
				// and merge with it
				else {
					ArrayList answers = (ArrayList) table_to_answer
							.get(table_name);
					for (int j = 0; j < answers.size(); j++) {
						Answer a = (Answer) answers.get(j);
						if (a.isMergeable()) {
							a.add(current_answer);
						}
					}
				}
			}
			// if the key does not exist, add a new entry
			else {
				ArrayList answers = new ArrayList();
				answers.add(current_answer);
				table_to_answer.put(table_name, answers);
			}
		}

		// place the merged answers back into our arraylist
		ArrayList new_answers = new ArrayList();
		Iterator it = table_to_answer.keySet().iterator();
		while (it.hasNext()) {
			ArrayList an = (ArrayList) table_to_answer.get(it.next());
			for (int i = 0; i < an.size(); i++) {
				new_answers.add(an.get(i));
			}
		}

		// replace old answer objects with new ones.
		this.answers = new_answers;
	}
}
